// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: Apache-2.0

package cmds

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"gitcode.com/lvupclub/lvup-api/api_serv/resource_serv/resource_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/resource_serv/resource_card_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/resource_serv/resource_exam_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_data_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_data_state_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_member_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_plan_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_qa_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/roadmap_serv/roadmap_rag_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/user_api_serv"
	"gitcode.com/lvupclub/lvup-api/api_serv/user_msg_api_serv"
	"gitcode.com/lvupclub/lvup-api/config"
	"gitcode.com/lvupclub/lvup-api/dao"
	"gitcode.com/lvupclub/proto-gen-go.git/src/resource_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/resource_card_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/resource_exam_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_data_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_data_state_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_member_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_plan_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_qa_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_rag_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/user_api"
	"gitcode.com/lvupclub/proto-gen-go.git/src/user_msg_api"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	"github.com/improbable-eng/grpc-web/go/grpcweb"
	"github.com/spf13/cobra"
	"google.golang.org/grpc"
)

var ServCmd = &cobra.Command{
	Use: "serv",
	RunE: func(cmd *cobra.Command, args []string) error {
		servCfg, err := config.ReadConfig(CommonFlagConfig)
		if err != nil {
			return err
		}
		err = dao.InitDao(servCfg)
		if err != nil {
			return err
		}

		exitChan := make(chan error, 10)
		go func() {
			sigChan := make(chan os.Signal, 1)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
			<-sigChan
			exitChan <- errors.New("catch signal")
		}()

		go runGpcServer(servCfg, exitChan)
		err = <-exitChan
		return err
	},
}

func runGpcServer(servCfg *config.ServerConfig, exitChan chan error) {
	optionList := []grpc.ServerOption{
		grpc.StreamInterceptor(
			grpc_middleware.ChainStreamServer(
				grpc_recovery.StreamServerInterceptor(),
			)),
		grpc.UnaryInterceptor(
			grpc_middleware.ChainUnaryServer(
				grpc_recovery.UnaryServerInterceptor(),
			)),
	}

	grpcServer := grpc.NewServer(optionList...)
	roadmap_api.RegisterRoadmapApiServer(grpcServer, &roadmap_api_serv.RoadmapApiImpl{})
	roadmap_data_api.RegisterRoadmapDataApiServer(grpcServer, &roadmap_data_api_serv.RoadmapDataApiImpl{})
	roadmap_data_state_api.RegisterRoadmapDataStateApiServer(grpcServer, &roadmap_data_state_api_serv.RoadmapDataStateApiImpl{})
	roadmap_member_api.RegisterRoadmapMemberApiServer(grpcServer, &roadmap_member_api_serv.RoadmapMemberApiImpl{})
	roadmap_qa_api.RegisterRoadmapQaApiServer(grpcServer, &roadmap_qa_api_serv.RoadmapQaApiImpl{})
	roadmap_rag_api.RegisterRoadmapRagApiServer(grpcServer, &roadmap_rag_api_serv.RoadmapRagApiImpl{})
	roadmap_plan_api.RegisterRoadmapPlanApiServer(grpcServer, &roadmap_plan_api_serv.RoadmapPlanApiImpl{})

	resource_api.RegisterResourceApiServer(grpcServer, &resource_api_serv.ResourceApiImpl{})
	resource_card_api.RegisterResourceCardApiServer(grpcServer, &resource_card_api_serv.ResourceCardApiImpl{})
	resource_exam_api.RegisterResourceExamApiServer(grpcServer, &resource_exam_api_serv.ResourceExamApiImpl{})

	user_api.RegisterUserApiServer(grpcServer, user_api_serv.NewUserApiImpl(&servCfg.Login))
	user_msg_api.RegisterUserMsgApiServer(grpcServer, &user_msg_api_serv.UserMsgApiImpl{})

	wrappedGrpc := grpcweb.WrapServer(grpcServer,
		grpcweb.WithOriginFunc(func(_ string) bool { return true }),
		grpcweb.WithCorsForRegisteredEndpointsOnly(false),
		grpcweb.WithWebsockets(true),
		grpcweb.WithWebsocketOriginFunc(func(_ *http.Request) bool { return true }),
	)
	serveMux := http.NewServeMux()
	serveMux.Handle("/", wrappedGrpc)

	httpServer := &http.Server{
		Handler: serveMux,
	}

	li, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", servCfg.ServPort))
	if err != nil {
		exitChan <- err
		return
	}
	if servCfg.TlsCertFile == "" && servCfg.TlsKeyFile == "" {
		err = httpServer.Serve(li)
		if err != nil {
			exitChan <- err
			return
		}
	} else {
		err = httpServer.ServeTLS(li, servCfg.TlsCertFile, servCfg.TlsKeyFile)
		if err != nil {
			exitChan <- err
			return
		}
	}
}
